using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace SharpMud.Net
{
    public class SessionStateStack : ISessionStateStack
    {
        #region Private Variables
        private System.Collections.GenericStack<ISessionState> _Stack;
        private ISessionState _ParentState;
        private string _StateID;
        private IHostedConnectionHandler _Session;
        #endregion

        #region Constructors
        private SessionStateStack()
        {
            _Stack = new GenericStack<ISessionState>();
        }
        public SessionStateStack(string stateID)
            : this(null, stateID)
        {
        }
        public SessionStateStack(ISessionState parentState, string stateID)
            : this()
        {
            _ParentState = parentState;
            _StateID = stateID;
        }
        #endregion

        #region IStack Members

        public void Clear()
        {
            _Stack.Clear();
        }

        object IStack.Pop()
        {
            return _Stack.Pop();
        }

        public ISessionState Pop()
        {
            return (ISessionState)_Stack.Pop();
        }

        void IStack.Push(object value)
        {
            _Stack.Push((ISessionState)value);
        }

        public void Push(ISessionState value)
        {
            Push(value, true);
        }

        public void Push(ISessionState value, bool autoInitialize)
        {
            if (autoInitialize && value.ParentState == null)
            {
                value.Initialize(_Session, this);
            }
            _Stack.Push(value);
        }

        object IStack.Peek()
        {
            return _Stack.Peek();
        }

        public ISessionState Peek()
        {
            if (_Stack.Count <= 0)
                return null;
            else
                return _Stack.Peek();
        }

        #endregion

        #region ICollection Members

        public bool IsSynchronized
        {
            get
            {
                return _Stack.IsSynchronized;
            }
        }

        public int Count
        {
            get
            {
                return _Stack.Count;
            }
        }

        public void CopyTo(Array array, int index)
        {
            _Stack.CopyTo(array, index);
        }

        public object SyncRoot
        {
            get
            {
                return _Stack.SyncRoot;
            }
        }

        #endregion

        #region IEnumerable Members

        public System.Collections.IEnumerator GetEnumerator()
        {
            return _Stack.GetEnumerator();
        }

        #endregion

        #region ISessionState Members

        public void Initialize(IHostedConnectionHandler session,ISessionState parentState)
        {
            this._ParentState = parentState;
            this._Session = session;
        }

        public ISessionState ParentState
        {
            get
            {
                return this._ParentState;
            }
        }

        public void Pulse()
        {
            ClearInactive();
            if(this.Count > 0)
            { this.Peek().Pulse(); }
        }

        private void ClearInactive()
        {
            while (this.Count > 0)
            {
                if (this.Peek().StillActive == false)
                {
                    this.Peek().Dispose();
                    this.Pop();
                }
                else
                {
                    break;
                }
            }
        }

        public string StateID
        {
            get
            {
                return this._StateID;
            }
        }

        public bool StillActive
        {
            get
            {
                if (this.Count > 0)
                    return true;
                else
                    return false;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            while (this.Count > 0)
            {
                this.Pop().Dispose();
            }
        }

        #endregion

        #region IStack Members


        bool IStack.Contains(object value)
        {
            return ((IStack)(_Stack)).Contains(value);
        }

        object[] IStack.Peek(int count)
        {
            return ((IStack)(_Stack)).Peek(count);
        }

        object[] IStack.Pop(int count)
        {
            return ((IStack)(_Stack)).Pop(count);
        }

        object[] IStack.ToArray()
        {
            return ((IStack)(_Stack)).ToArray();
        }

        #endregion


        #region IStack<ISessionState> Members

        ISessionState IStack<ISessionState>.Peek()
        {
            return _Stack.Peek();
        }

        ISessionState[] IStack<ISessionState>.Peek(int count)
        {
            return _Stack.Peek(count);
        }

        void IStack<ISessionState>.Push(ISessionState value)
        {
            _Stack.Push(value);
        }

        ISessionState IStack<ISessionState>.Pop()
        {
            return _Stack.Pop();
        }

        ISessionState[] IStack<ISessionState>.Pop(int count)
        {
            return _Stack.Pop(count);
        }

        ISessionState[] IStack<ISessionState>.ToArray()
        {
            return _Stack.ToArray();
        }

        bool IStack<ISessionState>.Contains(ISessionState value)
        {
            return _Stack.Contains(value);
        }
        
        #endregion

        #region IDisposable Members

        void IDisposable.Dispose()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }

    public class SessionStateStack<TSession> : ISessionStateStack<TSession> where TSession : IHasSessionState<TSession>
    {
        #region Private Variables
        private System.Collections.GenericStack<ISessionState<TSession>> _Stack;
        private ISessionState<TSession> _ParentState;
        private string _StateID;
        private TSession _Session;
        #endregion

        #region Constructors
        private SessionStateStack()
        {
            _Stack = new GenericStack<ISessionState<TSession>>();
        }
        public SessionStateStack(string stateID)
            : this(null, stateID)
        {
        }
        public SessionStateStack(ISessionState<TSession> parentState, string stateID)
            : this()
        {
            _ParentState = parentState;
            _StateID = stateID;
        }
        #endregion

        #region IStack Members

        #region Other Methods
        public void Clear()
        {
            _Stack.Clear();
        }

        bool IStack.Contains(object value)
        {
            return ((IStack)(_Stack)).Contains(value);
        }

        object[] IStack.ToArray()
        {
            return (object[])((System.Array)(_Stack.ToArray()));
        }
        ISessionState[] IStack<ISessionState>.ToArray()
        {
            return (ISessionState[])((System.Array)(_Stack.ToArray()));
        }
        public ISessionState<TSession>[] ToArray()
        {
            return _Stack.ToArray();
        }
        #endregion

        #region Pop()
        object IStack.Pop()
        {
            return _Stack.Pop();
        }
        ISessionState IStack<ISessionState>.Pop()
        {
            return _Stack.Pop();
        }
        public ISessionState<TSession> Pop()
        {
            return _Stack.Pop();
        }
        object[] IStack.Pop(int count)
        {
            return _Stack.Pop(count);
        }
        ISessionState[] IStack<ISessionState>.Pop(int count)
        {
            return _Stack.Pop(count);
        }
        public ISessionState<TSession>[] Pop(int count)
        {
            return _Stack.Pop(count);
        }
        #endregion

        #region Push()
        void IStack.Push(object value)
        {
            this.Push((ISessionState<TSession>)value,true);
        }

        void IStack<ISessionState>.Push(ISessionState value)
        {
            this.Push((ISessionState<TSession>)value,true);
        }
        void ISessionStateStack.Push(ISessionState value, bool autoInitialize)
        {
            this.Push((ISessionState<TSession>)value, autoInitialize);
        }

        public void Push(ISessionState<TSession> value)
        {
            this.Push(value, true);
        }

        public void Push(ISessionState<TSession> value, bool autoInitialize)
        {
            if (autoInitialize)
            {
                value.Initialize(_Session, this);
            }
            _Stack.Push(value);
        }
        #endregion

        #region Peek()
        object IStack.Peek()
        {
            return _Stack.Peek();
        }

        object[] IStack.Peek(int count)
        {
            return ((IStack)(_Stack)).Peek(count);
        }

        public ISessionState<TSession> Peek()
        {
            if (_Stack.Count <= 0)
                return null;
            else
                return _Stack.Peek();
        }
        public ISessionState<TSession>[] Peek(int count)
        {
            return _Stack.Peek(count);
        }

        ISessionState IStack<ISessionState>.Peek()
        {
            return _Stack.Peek();
        }

        ISessionState[] IStack<ISessionState>.Peek(int count)
        {
            return _Stack.Peek(count);
        }

        ISessionState<TSession> IStack<ISessionState<TSession>>.Peek()
        {
            return _Stack.Peek();
        }

        ISessionState<TSession>[] IStack<ISessionState<TSession>>.Peek(int count)
        {
            return _Stack.Peek(count);
        }
        #endregion
        #endregion

        #region ICollection Members

        public bool IsSynchronized
        {
            get
            {
                return _Stack.IsSynchronized;
            }
        }

        public int Count
        {
            get
            {
                return _Stack.Count;
            }
        }

        public void CopyTo(Array array, int index)
        {
            _Stack.CopyTo(array, index);
        }

        public object SyncRoot
        {
            get
            {
                return _Stack.SyncRoot;
            }
        }

        #endregion

        #region IEnumerable Members

        public System.Collections.IEnumerator GetEnumerator()
        {
            return _Stack.GetEnumerator();
        }

        #endregion

        #region ISessionState Members

        public void Initialize(TSession session, ISessionState<TSession> parentState)
        {
            this._ParentState = parentState;
            this._Session = session;
        }

        public void Initialize(IHostedConnectionHandler session, ISessionState parentState)
        {
            Initialize((TSession)session, (ISessionState<TSession>)parentState);
        }

        public ISessionState<TSession> ParentState
        {
            get
            {
                return this._ParentState;
            }
        }

        ISessionState ISessionState.ParentState
        {
            get
            {
                return this._ParentState;
            }
        }

        public void Pulse()
        {
            ClearInactive();
            if (this.Count > 0)
            { this.Peek().Pulse(); }
        }

        private void ClearInactive()
        {
            while (this.Count > 0)
            {
                if (this.Peek().StillActive == false)
                {
                    this.Peek().Dispose();
                    this.Pop();
                }
                else
                {
                    break;
                }
            }
        }

        public string StateID
        {
            get
            {
                return this._StateID;
            }
        }

        public bool StillActive
        {
            get
            {
                if (this.Count > 0)
                    return true;
                else
                    return false;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            while (this.Count > 0)
            {
                this.Pop().Dispose();
            }
        }

        #endregion

        #region IStack<ISessionState<TSession>> Members

        ISessionState<TSession>[] IStack<ISessionState<TSession>>.ToArray()
        {
            return _Stack.ToArray();
        }

        public bool Contains(ISessionState<TSession> value)
        {
            return _Stack.Contains(value);
        }

        bool IStack<ISessionState>.Contains(ISessionState value)
        {
            return _Stack.Contains((ISessionState<TSession>)value);
        }

        #endregion
    }
}
